package com.baizhi;


import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class testShiro {

    /**
     *
     * 用户输入的账号和密码  假数据
     *
     */

    private String  username="lisi";
    private String  password="123456";

    /**
     * 登录功能  一定是 用户页面输入的账号密码 和 数据库中保存的账号密码
     * 作对比
     *
     * -数据中保存的账号和密码 (配置文件中的就是)
     *-用户页面输入的账号密码  写假数据
     *
     */
        @Test
        public void test1(){
//        通过shiro验证用户数据的账号密码是否正确
//        1.通过shiro读取配置文件数据 （相当于获取到数据库数据）
//        通过安全管理器工厂 读取到配置文件  再通过工厂获取安全管理对象
//        （可以认为将配置文件数据放到了安全管理器中）
            IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = iniSecurityManagerFactory.getInstance();

//        2.将安全管理器和Subject建立联系
            SecurityUtils.setSecurityManager(securityManager);
//        3.获取Subject
            Subject subject = SecurityUtils.getSubject();

//        4.将用户输入的账号密码封装到token中  令牌：封装认证数据（身份信息）
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);

//        5.调用Subject的login方法完成登录 login方法需要参数
//        token令牌（需要用户页面输入的账号密码）
            /**
             * login 就是验证 token中的身份信息（账号密码是否正确）
             * 方法没有返回值
             * login方法用抛异常方式告诉程序员有没有登录成功
             * - 没有异常就是登录成功
             * - UnknownAccountException 不知道账户异常 账户不存在
             * - IncorrectCredentialsException 密码不正确  Credential 凭证信息就是密码的意思
             */

            try{
                subject.login(token);
                System.out.println("认证成功");
            }catch (Exception e){
                /**
                 * subject.login(token); 报任何异常都是认证失败
                 */
                e.printStackTrace();
                System.out.println("认证失败");
            }
        }
        @Test
        public  void  Test2(){
            /**
             *
             * DigestUtils.md5Hex 加密
             *123456  每次的加密的结果都一样
             *
             * 加盐salt :给123456  加一个随机的字符串(盐值)在进行加密
             *
             * 多次加密叫散列
             *
             */

            String s= DigestUtils.md5Hex("123456"+"hhh");

            for (int i = 0; i <1024; i++) {
                s=DigestUtils.md5Hex(s);

            }
            System.out.println(s);

        }


    /**
     * 测试 shiro的加密工具类
     *
     *  Md5Hash()
     *  参数1 要进行加密的字符串
     *  参数2 盐值
     *  参数3 散列的次数
     */
    @Test
    public void test3(){
        Md5Hash hash = new Md5Hash("123456", "hhhh", 1024);

//        获取加密后的结果
        String s = hash.toHex();

        System.out.println(s);
    }
    /**
     * 登录  注册的流程发生了改变
     *
     * 1.用户注册的时候  随机出来一个随机字符串(盐值)
     * 2.通过用户注册的密码+盐值   进行加密处理(多次散列)
     *
     * 3.最终会得到一个加密文件 和盐值  储存在数据库中
     * 4.数据库中 不存储铭文 储存加密后的结果
     *
     * 登录流程
     * 1.接收到用户输入的账号密码
     * 2.通过账号查询数据库  得到用户在数据库中保存的 密文和盐值(不能直接比较)
     * 3.将用户输入的密码 +  数据库查询的盐值  做加密处理{多次加密}
     * 4.拿着用户输入的密码  加密后的密文和数据库中查询到的密文作比较
     * 5.如果一样  说明密码正确  登陆成功
     */


    /**
     * 授权的测试类
     *
     * 先认证后授权
     */
    @Test
    public void test4(){
        /**
         * 先写认证的代码
         */
//        1.读取配置文件
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

//        2.安全管理器赋值给工具类
        SecurityUtils.setSecurityManager(securityManager);

//        3.通过工具类获取Subject
        Subject subject = SecurityUtils.getSubject();

//        4.用户输入的账号密码封装token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

//        5.认证
        try {
            subject.login(token);
            System.out.println("认证成功");
        }catch (Exception e){
            System.out.println("认证失败");
        }

        /**
         * 开始授权
         */
//        1.验证主体的认证状态 有没有认证成功
//        isAuthenticated(); 返回值为true 代表当前主体已经认证成功
        boolean authenticated = subject.isAuthenticated();

        if (authenticated){
//            2.认证成功开始授权 【代码式授权】通过调用方法来验证主体有没有权限  可以做流程的控制

//            2.1 验证当前主体有没有 删除用户 的权限
            /**
             * isPermitted("user:delete"); 查看当前主体有没有 user:delete 这样的一个字符串
             * 如果有 返回值 true 代码当前用户拥有删除用户的权限
             */
            boolean permitted = subject.isPermitted("user:delete");

            if (permitted){
//                删除用户的方法写在if中
                System.out.println("当用户有删除用户的权限 可以调用删除用户方法");
            }

//            2.2 验证当前主体 有没有 vip1 的角色
            /**
             * subject.hasRole("vip1"); 查看当前主体有没有 vip1 的角色  如果有 返回值 true
             */
            boolean vip1 = subject.hasRole("vip1");

            if (vip1){
                System.out.println("拥有vip1的角色");
            }
        }
    }

}
